package com.societyGames.robotsExercises
{
import com.greensock.easing.Sine;
import com.societyGames.action.ActionQueue;
import com.societyGames.action.MoveToAction;

import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.text.TextLineMetrics;
import flash.utils.Dictionary;

public class RobotsRender extends Sprite
{
  private const _spaceWidth:int = 50;
  private const _spaceHeight:int = 50;

  [Embed(source="../../../../../RobotExercises/assets/House.png")]
  private static var HouseTileClass:Class;

  [Embed(source="../../../../../RobotExercises/assets/Start.png")]
  private static var TargetClass:Class;

  [Embed(source="../../../../../RobotExercises/assets/BackTile.png")]
  private static var BackTileClass:Class;

  [Embed(source="../../../../../RobotExercises/assets/FrontTile.png")]
  private static var FrontTileClass:Class;

  [Embed(source="../../../../../RobotExercises/assets/Wall.png")]
  private static var WallTileClass:Class;

  private var _robotSimulation:RobotsSimulation;
  private var _mainSprite:Sprite = new Sprite();
  private var _homeSprite:DisplayObject;
  private var _actionQueue:ActionQueue;
  private var _numberWidth:int = 0;
  private var _numberHeight:int = 0;
  private var _homePosition:Point;
  private var _nameToRobotImage:Dictionary = new Dictionary(); //name:String -> robotImage:RobotImage

  private const ROBOT_OFFSET_X:Number = -25;
  private const ROBOT_OFFSET_Y:Number = -25;

  private const HOME_OFFSET_X:Number = -25;
  private const HOME_OFFSET_Y:Number = -28;

  private const TILE_OFFSET_X:Number = -28;
  private const TILE_OFFSET_Y:Number = -28;

  private const WALL_OFFSET_X:Number = -20;
  private const WALL_OFFSET_Y:Number = -18;

  private const ILLEGAL_MOVE_PERCENT:Number = 0.25;

  private const ROBOT_MOVE_TIME:Number = 1;

  public function RobotsRender(robotSimulation:RobotsSimulation, actionQueue:ActionQueue)
  {
    this._robotSimulation = robotSimulation;
    this._actionQueue = actionQueue;

    addTilesTo(this._mainSprite);

    this._homeSprite = new HouseTileClass();
    this._mainSprite.addChild(this._homeSprite);

    this._mainSprite.x = this._numberWidth;
    this._mainSprite.y = this._numberHeight;
    this.addChild(this._mainSprite);
  }

  private function addTilesTo(parentSprite:Sprite):void
  {
    var gridWidth:int = this._robotSimulation.gridWidth;
    var gridHeight:int = this._robotSimulation.gridHeight;

    for (var gridX:int = 0; gridX < gridWidth; gridX++)
    {
      for (var gridY:int = 0; gridY < gridHeight; gridY++)
      {
        var childSprite:DisplayObject;
        if (gridY < gridHeight - 1)
        {
          childSprite = new BackTileClass();
        }
        else
        {
          childSprite = new FrontTileClass();
        }

        childSprite.x = gridX * this._spaceWidth + TILE_OFFSET_X;
        childSprite.y = gridY * this._spaceHeight + TILE_OFFSET_Y;
        parentSprite.addChild(childSprite);
      }
    }
  }

  public function showNumbers():void
  {
    var gridWidth:int = this._robotSimulation.gridWidth;
    var gridHeight:int = this._robotSimulation.gridHeight;
    var textField:TextField;
    //Calculate a sample first
    textField = createNumberTextField(0);
    //Grab values if we had a text field.
    this._numberWidth = textField.width;
    this._numberHeight = textField.height;
    //Draw x axis numbers
    var xPosition:Number = -this._spaceWidth / 2;
    for (var gridX:int = 0; gridX < gridWidth; gridX++)
    {
      textField = createNumberTextField(gridX);
      textField.x = xPosition + (_spaceWidth / 2 - textField.width / 2);
      textField.y = -(_spaceHeight / 2) - textField.textHeight;
      this.addChild(textField);
      xPosition += this._spaceWidth;
    }
    //Draw y axis numbers
    var yPosition:Number = -this._spaceHeight / 2;
    for (var gridY:int = 0; gridY < gridHeight; gridY++)
    {
      textField = createNumberTextField(gridY);
      textField.x = (-this._spaceWidth / 2) - textField.width;
      textField.y = yPosition + (_spaceHeight / 2 - textField.height / 2);
      this.addChild(textField);
      yPosition += this._spaceHeight;
    }
  }

  private function createNumberTextField(value:int):TextField
  {
    var textField:TextField = new TextField();
    textField.text = value.toString();
    var textFormat:TextFormat = textField.getTextFormat();
    textFormat.align = TextFormatAlign.CENTER;
    textField.setTextFormat(textFormat);
    var metrics:TextLineMetrics = textField.getLineMetrics(0);
    textField.width = metrics.width + 4;
    textField.height = metrics.height + 4;

    return textField;
  }

  public function setHome(position:Point):void
  {
    this._homePosition = position;
    this._homeSprite.x = this._homePosition.x * this._spaceWidth + HOME_OFFSET_X;
    this._homeSprite.y = this._homePosition.y * this._spaceHeight + HOME_OFFSET_Y;
  }

  public function createRobot(name:String, position:Point):void
  {
    var robotImage:RobotImage = new RobotImage(); //TODO: Choose which robot image we want!
    _nameToRobotImage[name] = robotImage;
    this._mainSprite.addChild(robotImage);

    robotImage.x = position.x * this._spaceWidth + ROBOT_OFFSET_X;
    robotImage.y = position.y * this._spaceHeight + ROBOT_OFFSET_Y;
    setRobotExpression(robotImage, position.x, position.y);
  }

  public function placeWall(x:int, y:int):void
  {
    var wallSprite:DisplayObject = new WallTileClass();
    wallSprite.x = x * this._spaceWidth + WALL_OFFSET_X;
    wallSprite.y = y * this._spaceHeight + WALL_OFFSET_Y;
    _mainSprite.addChild(wallSprite);
  }

  public function placeButton(x:int, y:int):void
  {
    var wallSprite:DisplayObject = new WallTileClass();
    wallSprite.x = x * this._spaceWidth + WALL_OFFSET_X;
    wallSprite.y = y * this._spaceHeight + WALL_OFFSET_Y;
    _mainSprite.addChild(wallSprite);
  }

  private function placeItem(imageClass:Class, x:int, y:int):void
  {
    var sprite:DisplayObject = new imageClass();
    sprite.x = x * this._spaceWidth + WALL_OFFSET_X;
    sprite.y = y * this._spaceHeight + WALL_OFFSET_Y;
    _mainSprite.addChild(sprite);
  }

  public function moveRobot(name:String, endX:int, endY:int):void
  {
    var robotImage:RobotImage = this._nameToRobotImage[name];
    this._actionQueue.add(new MoveToAction(
            robotImage,
            endX * this._spaceWidth + ROBOT_OFFSET_X,
            endY * this._spaceHeight + ROBOT_OFFSET_Y,
            ROBOT_MOVE_TIME,
            Sine.easeInOut
    ));
    setRobotExpression(robotImage, endX, endY);
  }

  public function moveIllegal(name:String, startX:int, startY:int, endX:int, endY:int):void
  {
    var robotImage:RobotImage = this._nameToRobotImage[name];
    this._actionQueue.add(new MoveToAction(
            robotImage,
            (startX + (endX - startX) * ILLEGAL_MOVE_PERCENT) * this._spaceWidth + ROBOT_OFFSET_X,
            (startY + (endY - startY) * ILLEGAL_MOVE_PERCENT) * this._spaceHeight + ROBOT_OFFSET_Y,
            ROBOT_MOVE_TIME * ILLEGAL_MOVE_PERCENT,
            Sine.easeInOut
    ));
    this._actionQueue.add(new MoveToAction(
            robotImage,
            startX * this._spaceWidth + ROBOT_OFFSET_X,
            startY * this._spaceHeight + ROBOT_OFFSET_Y,
            ROBOT_MOVE_TIME * ILLEGAL_MOVE_PERCENT,
            Sine.easeInOut
    ));
  }

  private function calculateBoardOverlapPoint(endX:int, endY:int):Point
  {
    //TODO: Detect where it goes overboard.
    //Left, Right, Top, Bottom
    return null;
  }

  private function setRobotExpression(robotImage:RobotImage, endX:int, endY:int):void
  {
    if (endX == this._homePosition.x && endY == this._homePosition.y)
    {
      this._actionQueue.add(new ShowHappyRobotAction(robotImage));
    }
    else
    {
      this._actionQueue.add(new ShowSadRobotAction(robotImage));
    }
  }
}
}

import com.societyGames.action.Action;
import com.societyGames.robotsExercises.RobotImage;

class ShowHappyRobotAction extends Action
{
  private var _robotImage:RobotImage;

  public function ShowHappyRobotAction(robot:RobotImage)
  {
    this._robotImage = robot;
  }

  public override function startAction():void
  {
    _robotImage.showHappy();
    this._completeEventObject.dispatchEvent();
  }
}

class ShowSadRobotAction extends Action
{
  private var _robotImage:RobotImage;

  public function ShowSadRobotAction(robot:RobotImage)
  {
    this._robotImage = robot;
  }

  public override function startAction():void
  {
    _robotImage.showSad();
    this._completeEventObject.dispatchEvent();
  }
}
